window.requestAnimationFrame =
  window.requestAnimationFrame ||
  window.mozRequestAnimationFrame ||
  window.webkitRequestAnimationFrame ||
  window.msRequestAnimationFrame;

export function countUp(this: any, target: string, endVal: number, decimals: number, duration: number) {
  var self = this;
  this.d = document.getElementById(target);
  this.dec = decimals * 10 || 0;
  this.duration = duration * 1000 || 2000;

  this.startTime = null;
  this.frameVal = 0;

  this.easeOutExpo = function (t: number, b: number, c: number, d: number) {
    return c * (-Math.pow(2, -10 * t / d) + 1) + b;
  }
  this.stepUp = function (timestamp: number) {    
    if (self.startTime === null) self.startTime = timestamp;

    var progress = timestamp - self.startTime;

    self.frameVal = self.easeOutExpo(progress, 0, endVal, self.duration);

    if (self.dec > 0) {
      self.frameVal = Math.round(self.frameVal * self.dec) / self.dec;
      self.frameVal = (self.frameVal > endVal) ? endVal : self.frameVal;
    }

    self.d.innerHTML = self.addCommas(self.frameVal.toFixed(decimals));

    if (progress < self.duration) {
      requestAnimationFrame(self.stepUp);
    } else {

      self.d.innerHTML = self.addCommas(endVal.toFixed(decimals));
    }
  }
  this.start = function () {
    if (!isNaN(endVal) && endVal !== null) {
      requestAnimationFrame(self.stepUp);
    } else {      
      self.d.innerHTML = '--';
    }
    return false;
  }
  this.reset = function () {
    this.d.innerHTML = 0;
  }
  this.addCommas = function (nStr: string) {
    nStr += '';
    let x = nStr.split('.');
    let x1 = x[0];
    let x2 = x.length > 1 ? '.' + x[1] : '';
    var rgx = /(\d+)(\d{3})/;
    while (rgx.test(x1)) {
      x1 = x1.replace(rgx, '$1' + ',' + '$2');
    }
    return x1 + x2;
  }
}